import dns.resolver
import paramiko
from sqlalchemy.orm import Session
from model.certificate import Certificate
from schema.certificate_schema import CertificateCreate, CertificateUpdate, CertificateSchema
import logging
from datetime import datetime

from utils.dns_util import DNSUtil
from fastapi import HTTPException

logger = logging.getLogger("fast-run")


def get_certificate(db: Session, cert_id: int):
    return db.query(Certificate).filter(Certificate.id == cert_id).first()


def get_certificates(db: Session, skip: int = 0, limit: int = 100):
    return db.query(Certificate).offset(skip).limit(limit).all()


def create_certificate(db: Session, cert: CertificateCreate):
    db_cert = Certificate(
        domain=cert.domain,
        fullchain=cert.fullchain,
        privkey=cert.privkey,
        requested_at=datetime.utcnow()
    )
    db.add(db_cert)
    db.commit()
    db.refresh(db_cert)
    return db_cert


def update_certificate(db: Session, cert_id: int, cert: CertificateUpdate):
    db_cert = db.query(Certificate).filter(Certificate.id == cert_id).first()
    if not db_cert:
        return None
    db_cert.domain = cert.domain
    db_cert.fullchain = cert.fullchain
    db_cert.privkey = cert.privkey
    db.commit()
    db.refresh(db_cert)
    return db_cert


def delete_certificate(db: Session, cert_id: int):
    db_cert = db.query(Certificate).filter(Certificate.id == cert_id).first()
    if not db_cert:
        return None
    db.delete(db_cert)
    db.commit()
    return db_cert


def check_a_record(domain: str, host: str) -> bool:
    """
    检查指定域名是否有对应的主机 A 记录

    Args:
        domain: 要检查的域名
        host: 预期的主机名

    Returns:
        bool: 如果找到匹配的 A 记录返回 True，否则返回 False
    """
    try:
        # 解析域名的 A 记录
        answers = dns.resolver.resolve(domain, 'A')

        # 获取所有 IP 地址
        domain_ips = {str(rdata) for rdata in answers}
        host_ips = {host}

        logger.info(f"解析出domain 对应IP {domain_ips}")
        logger.info(f"需要包含的IP： {host_ips}")

        # 获取交集
        common_ips = domain_ips & host_ips
        logger.info(f"domain_ips: {domain_ips}, host_ips: {host_ips}, common: {common_ips}")

        if common_ips:
            return True
        else:
            raise HTTPException(status_code=400, detail=f"{domain} 没有 {host} 的A记录")

    except dns.resolver.NXDOMAIN:
        logger.error(f"{domain} 域名不存在")
        raise HTTPException(status_code=400, detail=f"{domain} 域名不存在")
    except dns.resolver.NoAnswer:
        # 没有 A 记录
        logger.warning(f"{domain} 没有 {host}  的A记录")
        raise HTTPException(status_code=400, detail=f"{domain} 没有 {host}  的A记录")



import paramiko
import logging

logger = logging.getLogger(__name__)

def apply_certificate(domain, host:str, user="root", password=None, email=None):
    """
    在远程服务器 host 上为 domain 申请 Let's Encrypt 证书 (standalone 模式)
    使用 paramiko ssh 连接，需要 ssh 免密或提供密码
    返回证书内容字典: {'cert': ..., 'privkey': ..., 'fullchain': ...}
    如果连接或操作失败，返回 None
    """
    if not DNSUtil.verify_domain(domain,[host]):
        raise HTTPException(status_code=404, detail=f"{domain} 没有找到{host} 的A记录\n 请检查配置的CNAME是否部署")

    if email is None:
        email = f"admin@{domain}"

    ssh = paramiko.SSHClient()
    ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())

    try:
        logger.info(f"尝试连接 {host}...")
        ssh.connect(hostname=host, username=user, password=password, timeout=10)
        logger.info(f"✅ 已连接到 {host}")
    except paramiko.ssh_exception.AuthenticationException:
        logger.error("SSH认证失败，请检查用户名或密码/密钥。")
        return None
    except paramiko.ssh_exception.SSHException as e:
        logger.error(f"SSH连接失败: {e}")
        return None
    except Exception as e:
        logger.error(f"无法连接到 {host}: {e}")
        return None

    try:
        # 检查 certbot
        stdin, stdout, stderr = ssh.exec_command("which certbot || echo not_installed")
        result = stdout.read().decode().strip()
        if "not_installed" in result:
            logger.info("certbot 未安装，正在远程安装...")
            ssh.exec_command("sudo apt-get update -y && sudo apt-get install -y certbot")
        else:
            logger.info("certbot 已安装。")

        # 停止 nginx
        ssh.exec_command("sudo nginx -s stop")

        # 申请证书
        cert_cmd = (
            f"sudo certbot certonly --standalone -d {domain} "
            f"--non-interactive --agree-tos -m {email} --preferred-challenges http"
        )
        logger.info(f"执行命令: {cert_cmd}")
        stdin, stdout, stderr = ssh.exec_command(cert_cmd)
        stdout.read()  # 等待完成
        stderr_output = stderr.read().decode()
        if stderr_output:
            logger.warning(f"certbot 输出错误信息: {stderr_output}")

        # 读取证书
        cert_paths = {
            'cert': f"/etc/letsencrypt/live/{domain}/cert.pem",
            'privkey': f"/etc/letsencrypt/live/{domain}/privkey.pem",
            'fullchain': f"/etc/letsencrypt/live/{domain}/fullchain.pem"
        }
        cert_data = {}
        try:
            with ssh.open_sftp() as sftp:
                for key, path in cert_paths.items():
                    try:
                        with sftp.file(path, 'r') as f:
                            cert_data[key] = f.read().decode()
                    except IOError:
                        logger.error(f"无法读取 {path}")
                        cert_data[key] = None
        except Exception as e:
            logger.error(f"SFTP操作失败: {e}")
            return None

        logger.info(f"✅ 已在 {host} 上申请证书，域名：{domain}")
        return cert_data

    finally:
        ssh.close()

